home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / misc1 / iv26_w30.zip / SOURCES / FILEBROW.C < prev    next >
C/C++ Source or Header  |  1992-01-17  |  12KB  |  491 lines

  1. /*
  2.  * Copyright (c) 1987, 1988, 1989 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Stanford not be used in advertising or
  9.  * publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  Stanford makes no representations about
  11.  * the suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  20.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  */
  22.  
  23. /*
  24.  * FileBrowser implementation.
  25.  */
  26.  
  27. #include <InterViews/filebrowser.h>
  28.  
  29. #include <string.h>
  30. #include <dir.h>
  31. #include <dos.h>
  32. #include <sys/stat.h>
  33.  
  34. /* #include <sys/param.h> */
  35. #define MAXPATHLEN 128
  36. #define MAXNAMLEN 128
  37.  
  38. /*****************************************************************************/
  39.  
  40. class FBDirectory {
  41. public:
  42.     FBDirectory(const char* name);
  43.     ~FBDirectory();
  44.  
  45.     boolean LoadDirectory(const char*);
  46.     const char* Normalize(const char*);
  47.     const char* ValidDirectories(const char*);
  48.  
  49.     int Index(const char*);
  50.     const char* File(int index);
  51.     int Count();
  52.  
  53.     boolean IsADirectory(const char*);
  54. private:
  55.     const char* Home(const char* = nil);
  56.     const char* ElimDot(const char*);
  57.     const char* ElimDotDot(const char*);
  58.     const char* InterpSlashSlash(const char*);
  59.     const char* InterpTilde(const char*);
  60.     const char* ExpandTilde(const char*, int);
  61.     const char* RealPath(const char*);
  62.  
  63.     boolean Reset(const char*);
  64.     void Clear();
  65.     void Check(int index);
  66.     void Insert(const char*, int index);
  67.     void Append(const char*);
  68.     void Remove(int index);
  69.     virtual int Position(const char*);
  70. private:
  71.     char** strbuf;
  72.     int strcount;
  73.     int strbufsize;
  74. };
  75.  
  76. inline int FBDirectory::Count () { return strcount; }
  77. inline void FBDirectory::Append (const char* s) { Insert(s, strcount); }
  78. inline const char* FBDirectory::File (int index) {
  79.     return (0 <= index && index < strcount) ? strbuf[index] : nil;
  80. }
  81.  
  82. inline char* strdup (const char* s) {
  83.     char* dup = new char[strlen(s) + 1];
  84.     strcpy(dup, s);
  85.     return dup;
  86. }
  87.  
  88. FBDirectory::FBDirectory (const char* name) {
  89.     const int defaultSize = 256;
  90.  
  91.     strbufsize = defaultSize;
  92.     strbuf = new char*[strbufsize];
  93.     strcount = 0;
  94.     LoadDirectory(name);
  95. }
  96.  
  97. FBDirectory::~FBDirectory () {
  98.     Clear();
  99. }
  100.  
  101. const char* FBDirectory::RealPath (const char* path) {
  102.     const char* realpath;
  103.  
  104.     if (*path == '\0') {
  105.     realpath = ".\\";
  106.     } else {
  107.     realpath = InterpTilde(InterpSlashSlash(path));
  108.     }
  109.     return realpath;
  110. }
  111.  
  112. boolean FBDirectory::LoadDirectory (const char* name) {
  113.     char buf[MAXPATHLEN+2];
  114.     const char* path = buf;
  115.  
  116.     strcpy(buf, ValidDirectories(RealPath(name)));
  117.     return Reset(buf);
  118. }
  119.  
  120. int FBDirectory::Index (const char* name) {
  121.     for (int i = 0; i < strcount; ++i) {
  122.     if (strcmp(strbuf[i], name) == 0) {
  123.         return i;
  124.     }
  125.     }
  126.     return -1;
  127. }
  128.  
  129. boolean FBDirectory::Reset (const char* path) {
  130.     boolean successful = IsADirectory(path);
  131.  
  132.     if (successful) {
  133.     Clear();
  134.     char* p = new char[128];
  135.     ffblk fbl;
  136.  
  137.     strcpy(p, path);
  138.     if (p[strlen(p)] == '\\') {
  139.         strcat(p, "*.*");
  140.     } else {
  141.        strcat(p, "\\*.*");
  142.     }
  143.  
  144.     int done = findfirst(p, &fbl, FA_DIREC);
  145.     while (!done) {
  146.         Insert(fbl.ff_name, Position(fbl.ff_name));
  147.         done = findnext(&fbl);
  148.     }
  149.  
  150.     delete p;
  151.     }
  152.  
  153. //    if (successful) {
  154. //    DIR* dir = opendir(path);
  155. //    Clear();
  156. //    for (struct direct* d = readdir(dir); d != NULL; d = readdir(dir)) {
  157. //        Insert(d->d_name, Position(d->d_name));
  158. //    }
  159. //    closedir(dir);
  160. //    }
  161.  
  162.     return successful;
  163. }
  164.  
  165. boolean FBDirectory::IsADirectory (const char* path) {
  166.     struct stat st;
  167.     return (
  168.     stat((char*)path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR
  169.     );
  170. }
  171.  
  172. const char* FBDirectory::Home (const char* name) {
  173.     static char dir[MAXNAMLEN+1];
  174.     return getcwd(dir, MAXNAMLEN+1);
  175.  
  176. //    struct passwd* pw =
  177. //    (name == nil) ? getpwuid(getuid()) : getpwnam(name);
  178. //    return (pw == nil) ? nil : pw->pw_dir;
  179. }
  180.  
  181. inline boolean DotSlash (const char* path) {
  182.     return
  183.     path[0] != '\0' && path[0] == '.' &&
  184.     (path[1] == '\\' || path[1] == '\0');
  185. }
  186.  
  187. inline boolean DotDotSlash (const char* path) {
  188.     return
  189.     path[0] != '\0' && path[1] != '\0' &&
  190.     path[0] == '.' && path[1] == '.' &&
  191.     (path[2] == '\\' || path[2] == '\0');
  192. }
  193.  
  194. const char* FBDirectory::Normalize (const char* path) {
  195.     static char newpath[MAXPATHLEN+1];
  196.     const char* buf;
  197.  
  198.     buf = InterpSlashSlash(path);
  199.     buf = ElimDot(buf);
  200.     buf = ElimDotDot(buf);
  201.     buf = InterpTilde(buf);
  202.  
  203.     if (*buf == '\0') {
  204.     strcpy(newpath, ".\\");
  205.  
  206.     } else if (!DotSlash(buf) && !DotDotSlash(buf) && *buf != '\\') {
  207.     strcpy(newpath, "\0");
  208. //    strcpy(newpath, ".\\");
  209.     strcat(newpath, buf);
  210.  
  211.     } else if (IsADirectory(buf) && buf[strlen(buf)-1] != '\\') {
  212.     strcpy(newpath, buf);
  213.     strcat(newpath, "\\");
  214.  
  215.     } else {
  216.     strcpy(newpath, buf);
  217.     }
  218.     return (const char*)newpath;
  219. }
  220.  
  221. const char* FBDirectory::ValidDirectories (const char* path) {
  222.     static char buf[MAXPATHLEN+1];
  223.     strcpy(buf, path);
  224.     int i = strlen(path);
  225.  
  226.     while (!IsADirectory(RealPath(buf)) && i >= 0) {
  227.     for (--i; buf[i] != '\\' && buf[i] != ':' && i >= 0; --i);
  228.     if (buf[i] != ':') {
  229.         buf[i] = '\0';
  230.     } else {
  231.         buf[i+1] = '\0';
  232.     }
  233.  
  234. //    for (--i; buf[i] != '\\' && i >= 0; --i);
  235. //    buf[i+1] = '\0';
  236.  
  237.     }
  238.     return buf;
  239. }
  240.  
  241. const char* FBDirectory::InterpSlashSlash (const char* path) {
  242.     for (int i = strlen(path)-1; i > 0; --i) {
  243.     if (path[i] == '\\' && path[i-1] == '\\') {
  244.         return &path[i];
  245.     }
  246.     }
  247.     return path;
  248. }
  249.  
  250. const char* FBDirectory::ElimDot (const char* path) {
  251.     static char newpath[MAXPATHLEN+1];
  252.     const char* src;
  253.     char* dest = newpath;
  254.  
  255.     for (src = path; src < &path[strlen(path)]; ++src) {
  256.     if (!DotSlash(src)) {
  257.         *dest++ = *src;
  258.  
  259.     } else if (*(dest-1) == '\\') {
  260.         ++src;
  261.  
  262.     } else {
  263.         *dest++ = *src;
  264.     }
  265.     }
  266.     *dest = '\0';
  267.     return newpath;
  268. }
  269.  
  270. static boolean CollapsedDotDotSlash (const char* path, const char*& start) {
  271.     if (path == start || *(start-1) != '\\') {
  272.     return false;
  273.  
  274.     } else if (path == start-1 && *path == '\\') {
  275.     return true;
  276.  
  277.     } else if (path == start-2) {               // NB: won't handle '//' right
  278.     start = path;
  279.     return *start != '.';
  280.  
  281.     } else if (path < start-2 && !DotDotSlash(start-3)) {
  282.     for (start -= 2; path <= start; --start) {
  283.         if (*start == '\\') {
  284.         ++start;
  285.         return true;
  286.         }
  287.     }
  288.     start = path;
  289.     return true;
  290.     }
  291.     return false;
  292. }
  293.  
  294. const char* FBDirectory::ElimDotDot (const char* path) {
  295.     static char newpath[MAXPATHLEN+1];
  296.     const char* src;
  297.     char* dest = newpath;
  298.  
  299.     for (src = path; src < &path[strlen(path)]; ++src) {
  300.     if (DotDotSlash(src) && CollapsedDotDotSlash((const char*)newpath, (const char*)dest)) {
  301.         src += 2;
  302.     } else {
  303.         *dest++ = *src;
  304.     }
  305.     }
  306.     *dest = '\0';
  307.     return newpath;
  308. }
  309.  
  310. const char* FBDirectory::InterpTilde (const char* path) {
  311.     static char realpath[MAXPATHLEN+1];
  312.     const char* beg = strrchr(path, '~');
  313.     boolean validTilde = beg != NULL && (beg == path || *(beg-1) == '\\');
  314.  
  315.     if (validTilde) {
  316.     const char* end = strchr(beg, '\\');
  317.     int length = (end == nil) ? strlen(beg) : end - beg;
  318.     const char* expandedTilde = ExpandTilde(beg, length);
  319.  
  320.     if (expandedTilde == nil) {
  321.         validTilde = false;
  322.     } else {
  323.         strcpy(realpath, expandedTilde);
  324.         if (end != nil) {
  325.         strcat(realpath, end);
  326.         }
  327.     }
  328.     }
  329.     return validTilde ? realpath : path;
  330. }
  331.  
  332. const char* FBDirectory::ExpandTilde (const char* tildeName, int length) {
  333.     const char* name = nil;
  334.  
  335.     if (length > 1) {
  336.     static char buf[MAXNAMLEN+1];
  337.     strncpy(buf, tildeName+1, length-1);
  338.     buf[length-1] = '\0';
  339.     name = buf;
  340.     }
  341.     return Home(name);
  342. }
  343.  
  344. void FBDirectory::Check (int index) {
  345.     char** newstrbuf;
  346.  
  347.     if (index >= strbufsize) {
  348.     strbufsize = (index+1) * 2;
  349.     newstrbuf = new char*[strbufsize];
  350.     memmove(newstrbuf, strbuf, strcount*sizeof(char*));
  351.     delete strbuf;
  352.     strbuf = newstrbuf;
  353.     }
  354. }
  355.  
  356. void FBDirectory::Insert (const char* s, int index) {
  357.     char** spot;
  358.     index = (index < 0) ? strcount : index;
  359.  
  360.     if (index < strcount) {
  361.     Check(strcount+1);
  362.     spot = &strbuf[index];
  363.     memmove(spot+1, spot, (strcount - index)*sizeof(char*));
  364.     } else {
  365.     Check(index);
  366.     spot = &strbuf[index];
  367.     }
  368.     char* string = strdup(s);
  369.     *spot = string;
  370.     ++strcount;
  371. }
  372.  
  373. void FBDirectory::Remove (int index) {
  374.     if (index < --strcount) {
  375.     char** spot = &strbuf[index];
  376.         delete spot;
  377.     memmove(spot, spot+1, (strcount - index)*sizeof(char*));
  378.     }
  379. }
  380.  
  381. void FBDirectory::Clear () {
  382.     for (int i = 0; i < strcount; ++i) {
  383.         delete strbuf[i];
  384.     }
  385.     strcount = 0;
  386. }
  387.  
  388. int FBDirectory::Position (const char* s) {
  389.     int i;
  390.  
  391.     for (i = 0; i < strcount; ++i) {
  392.         if (strcmp(s, strbuf[i]) < 0) {
  393.             return i;
  394.         }
  395.     }
  396.     return strcount;
  397. }
  398.  
  399. /*****************************************************************************/
  400.  
  401. FileBrowser::FileBrowser (
  402.     ButtonState* bs, const char* dir, int r, int c,
  403.     boolean u, int h, const char* d
  404. ) : (bs, r, c, u, h, d) {
  405.     Init(dir);
  406.     Update();
  407. }
  408.  
  409. FileBrowser::FileBrowser (
  410.     const char* name, ButtonState* bs, const char* dir, int r, int c,
  411.     boolean u, int h, const char* d
  412. ) : (name, bs, r, c, u, h, d) {
  413.     Init(dir);
  414.     Update();
  415. }
  416.  
  417. void FileBrowser::Init (const char* d) {
  418.     dir = new FBDirectory(d);
  419.     lastpath = strdup(ValidDirectories(Normalize(d)));
  420. }
  421.  
  422. FileBrowser::~FileBrowser () {
  423.     delete dir;
  424.     delete lastpath;
  425. }
  426.  
  427. static const char* Concat (const char* path, const char* file) {
  428.     static char buf[MAXPATHLEN+1];
  429.  
  430.     strcpy(buf, path);
  431.     if (path[strlen(path)-1] != '\\') {
  432.     strcat(buf, "\\");
  433.     }
  434.     return strcat(buf, file);
  435. }
  436.  
  437. boolean FileBrowser::IsADirectory (const char* path) {
  438.     return dir->IsADirectory(Normalize(path));
  439. }
  440.  
  441. boolean FileBrowser::SetDirectory (const char* path) {
  442.     boolean successful = true;
  443.     path = ValidDirectories(path);
  444.     const char* normpath = Normalize(path);
  445.  
  446.     if (strcmp(normpath, lastpath) != 0) {
  447.     char* newnormpath = strdup(normpath);
  448.     successful = dir->LoadDirectory(newnormpath);
  449.  
  450.     if (successful) {
  451.         delete lastpath;
  452.         lastpath = newnormpath;
  453.         Update();
  454.     } else {
  455.         delete newnormpath;
  456.     }
  457.     }
  458.     return successful;
  459. }
  460.  
  461. const char* FileBrowser::ValidDirectories (const char* path) {
  462.     return dir->ValidDirectories(path);
  463. }
  464.  
  465. const char* FileBrowser::Normalize (const char* path) {
  466.     return dir->Normalize(path);
  467. }
  468.  
  469. const char* FileBrowser::Path (int index) {
  470.     const char* s = String(index);
  471.  
  472.     return (s == nil ) ? nil : Normalize(Concat(lastpath, s));
  473. }
  474.  
  475. void FileBrowser::Update () {
  476.     Clear();
  477.  
  478.     for (int i = 0; i < dir->Count(); ++i) {
  479.         const char* name = dir->File(i);
  480.  
  481.         if (dir->IsADirectory(Concat(lastpath, name))) {
  482.         char buf[MAXPATHLEN+1];
  483.             strcpy(buf, name);
  484.         strcat(buf, "\\");
  485.             Append(buf);
  486.         } else {
  487.             Append(name);
  488.         }
  489.     }
  490. }
  491.